package cn.outsourcing.supermarket.service.impl;

import cn.outsourcing.supermarket.common.constants.CommonConstants;
import cn.outsourcing.supermarket.common.constants.WechatConstants;
import cn.outsourcing.supermarket.common.enums.WechatEnums;
import cn.outsourcing.supermarket.common.exception.SupermarketException;
import cn.outsourcing.supermarket.common.properties.WechatProperties;
import cn.outsourcing.supermarket.common.utils.*;
import cn.outsourcing.supermarket.dto.WxLoginMsgDTO;
import cn.outsourcing.supermarket.dto.WxUserInfoDTO;
import cn.outsourcing.supermarket.mapper.HiolabsUserMapper;
import cn.outsourcing.supermarket.po.HiolabsUser;
import cn.outsourcing.supermarket.service.HiolabsUserService;
import cn.outsourcing.supermarket.vo.WxUserVO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 超市用户服务类
 *
 * @author gzkemays
 * @since 2021-10-14
 */
@Service
public class HiolabsUserServiceImpl extends ServiceImpl<HiolabsUserMapper, HiolabsUser>
    implements HiolabsUserService {
  @Resource HiolabsUserMapper userMapper;

  @Value("${wechat.appid}")
  private String appid;

  @Override
  public WxUserVO login(WxLoginMsgDTO wxLoginMsg) {
    Map<String, String> wechat = DataUtils.entityParseMapWithStr(new WechatProperties());
    wechat.put(WechatConstants.JS_CODE, wxLoginMsg.getCode());
    // 解析登录 API
    String j2sUrl = EnumsOperaUtils.parseUrlAndArgsEnums(WechatEnums.LOGIN_API, wechat);
    // 获取解密信息
    JSONObject json = YzjHttp.goGetToJsonObj(j2sUrl);
    String openId = json.getString(WechatConstants.OPEN_ID);
    String sessionKey = json.getString(WechatConstants.SESSION_KEY);
    // 查询数据库是否已存在用户
    HiolabsUser hiolabsUser =
        userMapper.selectOne(
            Wrappers.<HiolabsUser>lambdaQuery().eq(HiolabsUser::getWeixinOpenid, openId));
    // 不存在则进行注册操作
    if (hiolabsUser == null) {
      String decrypt = decrypt(sessionKey, wxLoginMsg.getEncryptedData(), wxLoginMsg.getIv());
      if (JsonUtils.isJson(decrypt)) {
        return register(decrypt, openId, sessionKey);
      } else {
        throw new SupermarketException(CommonConstants.SECURITY_ERROR_CODE, "注册失败，请重试！");
      }
    }
    hiolabsUser.setLastLoginTime(DataUtils.getSeconds());
    userMapper.updateById(hiolabsUser);
    // 已存在的话，直接 copy 查询实体类已有参数，并携带 sessionKey 返回出去。
    return new WxUserVO(hiolabsUser, sessionKey);
  }

  @Override
  public HiolabsUser getUserMsg(String token) {
    Object openId = JwtUtils.settings().build().checkJwt(token).get(WechatConstants.OPEN_ID);
    return userMapper.selectOne(
        Wrappers.<HiolabsUser>lambdaQuery().eq(HiolabsUser::getWeixinOpenid, openId));
  }

  /**
   * 解密
   *
   * @param sessionKey J2S 密钥
   * @param encryptedData 微信小程序登录回来的加密密文
   * @param iv IV 向量
   * @return 用户信息
   */
  private String decrypt(String sessionKey, String encryptedData, String iv) {
    return DataUtils.decryptWxEncrypted(appid, sessionKey, encryptedData, iv);
  }

  /**
   * 新会员注册
   *
   * @param decrypt 解密明文
   * @param openId J2S 返回的 openId 微信用户凭证
   * @param sessionKey J2S 返回的 sessionKey
   * @return 构造新用户对象
   */
  private WxUserVO register(String decrypt, String openId, String sessionKey) {
    JSONObject deJson = JSONObject.parseObject(decrypt);
    String nickname = StrUtils.getBase64Str(deJson.getString(WechatConstants.INFO_NICKNAME_KEY));
    String username = WechatConstants.COMMON_WECHAT_NICK_PREFX + UUID.randomUUID();
    Boolean gender = deJson.getBoolean(WechatConstants.INFO_GENDER_KEY);
    String avatar = deJson.getString(WechatConstants.INFO_AVATAR_KEY);
    Integer currentSeconds = DataUtils.getSeconds();
    HiolabsUser user =
        HiolabsUser.builder()
            .nickname(nickname)
            .username(username)
            .password(openId)
            .registerTime(currentSeconds)
            .lastLoginTime(currentSeconds)
            .gender(gender)
            .avatar(avatar)
            .weixinOpenid(openId)
            .country(deJson.getString(WechatConstants.INFO_COUNTRY_KEY))
            .province(deJson.getString(WechatConstants.INFO_PROVINCE_KEY))
            .city(deJson.getString(WechatConstants.INFO_CITY_KEY))
            .build();
    // 进行数据插入，返回新ID
    userMapper.insert(user);
    return WxUserVO.builder()
        .token(
            JwtUtils.settings()
                .build()
                .createTokenByMapNotExp(
                    new HashMap<String, Object>(4) {
                      {
                        put(WechatConstants.SESSION_KEY, sessionKey);
                        put(WechatConstants.OPEN_ID, openId);
                        put("user_id", user.getId());
                      }
                    }))
        .userInfo(
            WxUserInfoDTO.builder()
                .id(user.getId())
                .nickname(StrUtils.getStrByBase64(nickname))
                .gender(gender)
                .avatar(avatar)
                .build())
        .is_new(true)
        .build();
  }
}
